
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.swing.JOptionPane;


public class MaquinaP {
	
	 //ATRIBUTOS
	 private Pila pila;
	 private Memoria mem;//memoria de datos
	 private String ruta;//ruta del fichero P
	 private String instruccion;
	 private int contProg;//contador de programa
	 
	private boolean fin;
	MemoriaInstrucciones memIns;
	 
	 public MaquinaP(String r,Memoria memoria){
		 
         ruta=r;
         fin=false;
         pila = new Pila();
         mem = memoria;
         contProg=0;
         memIns= new MemoriaInstrucciones(ruta);

    }

	public String sigInstruccion() throws IOException{
        return memIns.get(contProg);
       
    }
	
	public boolean leerInstruccion () throws FileNotFoundException, IOException{
		
        String inst = "";
        String dato="";

        instruccion=sigInstruccion();
        if (instruccion==null)
        	return false;
        String[] result = instruccion.split("[()]");
        inst=result[0];
        if (inst.equals("mueve")||inst.equals("new")||inst.equals("del")||inst.equals("apila")||inst.equals("apila-dir")||inst.equals("desapila-dir")||inst.equals("ir-a")||inst.equals("ir-f"))
        dato=result[1];

        //Ejecutamos la instrucci�n correspondiente a la instrucci�n le�da
 
        if (inst.equals("apila")){
            ejecuta_apila(dato);
            return true;
        }
        else if (inst.equals("del")){
            ejecuta_delete(dato);
            return true;
        }
        else if (inst.equals("ir-ind")){
            ejecuta_ind();
            return true;
        }
        else if (inst.equals("copia")){
            ejecuta_copia();
            return true;
        }
        else if (inst.equals("new")){
            ejecuta_new(dato);
            return true;
        }else if (inst.equals("mueve")){
            ejecuta_mueve(dato);
            return true;
        }
        else if (inst.equals("apila-ind")){
            ejecuta_apilaind();
            return true;
        }
        else if (inst.equals("desapila-ind")){
            ejecuta_desapilaind();
            return true;
        }
        else if (inst.equals("desapila")){
            ejecuta_desapila();
            return true;
        }
        else if (inst.equals("apila-dir")){
            ejecuta_apila_dir(dato);
            return true;
        }
        else if (inst.equals("desapila-dir")){
            ejecuta_desapila_dir(dato);
            return true;
        }
        else if (inst.equals("menor")){
            ejecuta_menor();
            return true;
        }
        else if (inst.equals("mayor")){
            ejecuta_mayor();
            return true;
        }
        else if (inst.equals("menorigual")){
            ejecuta_menorOigual();
            return true;
        }
        else if (inst.equals("mayorigual")){
            ejecuta_mayorOigual();
            return true;
        }
        else if (inst.equals("igual")){
            ejecuta_igual();
            return true;
        }
        else if (inst.equals("distinto")){
            ejecuta_distinto();
            return true;
        }
        else if (inst.equals("suma")){
            ejecuta_suma();
            return true;
        }
        else if (inst.equals("resta")){
            ejecuta_resta();
            return true;
        }
        else if (inst.equals("or")){
            ejecuta_or();
            return true;
        }
        else if (inst.equals("and")){
            ejecuta_and();
            return true;
        }
        else if (inst.equals("mul")){
            ejecuta_multiplicacion();
            return true;
        }
        else if (inst.equals("div")){
            ejecuta_division();
            return true;
        }
        else if (inst.equals("mod")){
            ejecuta_modulo();
            return true;
        }
        else if (inst.equals("not")){
            ejecuta_not();
            return true;
        }
        else if (inst.equals("menosUnario")){
            ejecuta_menosUnario();
            return true;
        }
        else if (inst.equals("cInt")){
            ejecuta_cInt();
            return true;
        }
        else if (inst.equals("cReal")){
            ejecuta_cReal();
            return true;
        }
        else if (inst.equals("in")){
            ejecuta_read();
            return true;
        }
        else if (inst.equals("out")){
            ejecuta_write();
            return true;
        }
        else if (inst.equals("ir-a")){
            ejecuta_ira(dato);
            return true;
        }
        else if (inst.equals("ir-f")){
            ejecuta_irf(dato);
            return true;
        }
        else if (inst.equals("STOP")){
            //System.exit(1);
            return false;
        }
       else{
    	   return false; //Si no corresponde a ninguna instruccion, devolvemos falso;
       }
        
    }
	
	private void ejecuta_ind() {
        String dato1 = pila.desapila();
        int aux1=Integer.valueOf(dato1);
        contProg=aux1-1;
		
	}

	private void ejecuta_copia() {
		pila.apila(pila.cima());
		contProg++;
		
	}

	private void ejecuta_mueve(String dato) {
		String dirfuente = pila.desapila();
		String dirdestino= pila.desapila();
		int auxdirfuente=Float.valueOf(dirfuente).intValue();
		int auxdirDestino=Float.valueOf(dirdestino).intValue();
		int auxdato=Float.valueOf(dato).intValue();
		mem.mueve(auxdirfuente,auxdirDestino, auxdato);
		contProg++;
		
	}

	private void ejecuta_new(String dato) {
		int aux=mem.newHeap(Integer.parseInt(dato));
		if (aux==-1){
			JOptionPane.showMessageDialog(null, "No hay mas memoria disponible.");
			fin=true;
		}else{
			pila.apila(String.valueOf(aux));
			contProg++;
		
		}
	}

	private void ejecuta_delete(String dato) {
		String dir = pila.desapila();
		if(!(dir.equals("null"))){
			int auxdir=Float.valueOf(dir).intValue();
			mem.delHeap(Integer.parseInt(dato),auxdir);
	    }
		
		contProg++;
	}

	private void ejecuta_apilaind() {
		String dir = pila.desapila();
		if(dir.equals("null")){
        	JOptionPane.showMessageDialog(null, "null pointer exception.");
        	fin=true;
        }else{
	        int auxdir=Float.valueOf(dir).intValue();
	        if(mem.getDato(auxdir).equals("del")){
	        	JOptionPane.showMessageDialog(null, "fallo de segmentacion.");
	        	fin=true;
	        }
	        
	        else pila.apila(mem.getDato(auxdir));
	        contProg++;
        }
	}

	private void ejecuta_desapilaind() {
		String dato = pila.desapila();
        String dir = pila.desapila();
        if(dir.equals("null")){
        	JOptionPane.showMessageDialog(null, "null pointer exception.");
        	fin=true;
        }else{
	        int auxdir=Float.valueOf(dir).intValue();
	        mem.setDato(auxdir, dato);
	        pila.apila(dato);
	        contProg++;
        }
	}

	private void ejecuta_irf(String dato) {
		int aux = Integer.decode(dato);
        String dato1 = pila.desapila();
        float aux1=Float.valueOf(dato1);
        if (aux1==0)contProg=aux-1;
        else contProg++;

		
	}

	private void ejecuta_ira(String dato) {
		int aux = Integer.decode(dato);
        contProg=aux-1;
		
	}

	//Funciones implementadas en base a nuestra memoria
	
	private void ejecuta_desapila() {
		pila.desapila();
		contProg++;
		
	}

	public void ejecuta_apila(String num){
        pila.apila(num);
        contProg++;
    }
	
	public void ejecuta_apila_dir(String num){
        int aux = Integer.decode(num);
        if(mem.getDato(aux).equals("del")){
        	JOptionPane.showMessageDialog(null, "fallo de segmentacion.");
        	fin=true;
        }
        else pila.apila(mem.getDato(aux));
        contProg++;
    }
	
	public void ejecuta_desapila_dir(String num){
        String aux = pila.desapila();
        int dir = Integer.decode(num);
        mem.setDato(dir, aux);
        contProg++;
    }
	
	public void ejecuta_menor(){
        String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux1<aux2)datoRes="1";
        else datoRes="0";
        pila.apila(datoRes);
        contProg++;
    }
	
	public void ejecuta_mayor(){
        String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux1>aux2)datoRes="1";
        else datoRes="0";
        pila.apila(datoRes);
        contProg++;
    }
	
	private void ejecuta_menorOigual() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux1<=aux2)datoRes="1";
        else datoRes="0";
        pila.apila(datoRes);
        contProg++;
	}
	
	private void ejecuta_mayorOigual() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux1>=aux2)datoRes="1";
        else datoRes="0";
        pila.apila(datoRes);
        contProg++;
	}
	
	private void ejecuta_igual() {
		String datoRes = "";
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        if(dato1.equals("null")||dato2.equals("null")){
        	if (dato2.equals(dato1))datoRes="1";
            else datoRes="0";
        }else{
	        float aux2=Float.valueOf(dato2);
	        float aux1=Float.valueOf(dato1);
	        if (aux1==aux2)datoRes="1";
	        else datoRes="0";
	    }
        pila.apila(datoRes);
        contProg++;
	}
	
	private void ejecuta_distinto() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux1!=aux2)datoRes="1";
        else datoRes="0";
        pila.apila(datoRes);
        contProg++;
	}

	private void ejecuta_suma() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        aux1+=aux2;
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_resta() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        aux1-=aux2;
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_multiplicacion() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        aux2*=aux1;
        datoRes=String.valueOf(aux2);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_division() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        //hay que revisar que no dividamos por cero
        if(aux2==0){
        	System.out.println("Excepcion:Division por 0");
        	fin=true;
        }
        aux1=aux1/aux2;
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_modulo() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if(aux2==0){
        	System.out.println("Excepcion:Division por 0");
        	fin=true;
        }
        aux1=aux1%aux2;
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_or() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux2==0&&aux1==0)datoRes="0";
        else datoRes="1";
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_and() {
		String dato2 = pila.desapila();
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux2=Float.valueOf(dato2);
        float aux1=Float.valueOf(dato1);
        if (aux2!=0&&aux1!=0)datoRes="1";
        else datoRes="0";
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_not() {
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux1=Float.valueOf(dato1);
        if (aux1!=0)datoRes="0";
        else datoRes="1";
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_menosUnario() {
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux1=Float.valueOf(dato1);
        aux1=-aux1;
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_cInt() { //Casting (int)
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux1=Float.valueOf(dato1);
        aux1=(int)aux1;
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	private void ejecuta_cReal() { //Casting (real)
        String dato1 = pila.desapila();
        String datoRes = "";
        float aux1=Float.valueOf(dato1);
        datoRes=String.valueOf(aux1);
        pila.apila(datoRes);
        contProg++;
		
	}
	
	public void ejecuta_write(){//instrucci�n out
        String dato1 = pila.cima();
        Interface.setTextArea3("OUT:" + " " +dato1);
        contProg++;
    }
	
	public void ejecuta_read() throws NumberFormatException,IOException{ 	//instruccion in
        @SuppressWarnings("unused")
		float resFloat;
        String datoRes ="";
        boolean malo=true; //Para saber si el n�mero introducido por pantalla es correcto o no
        
        while(malo){
        try {	
        	malo=false;
        	datoRes = JOptionPane.showInputDialog("Escriba el dato"); 
            resFloat = Float.valueOf(datoRes);        
            }
        catch (NumberFormatException e){ 
             malo=true;
             JOptionPane.showMessageDialog(null,"El numero no es correcto."); 
            }
        }
        pila.apila(datoRes); //Apilamos el dato le�do y seguimos con la siguiente instrucci�n
        contProg++;
    }
	
	//Imprime el contenido de la pila por pantalla
	
    public void imprimePila(){
        pila.toString();
    }

    //Imprime el contenido de la memoria por pantalla

    public void ejecutar(int nflag){
        try {
        	if(nflag == 0){
                while (leerInstruccion()&&fin==false) {
                    //contProg++;
                }
                this.imprimePila();
             }
            else{
                
                while(leerInstruccion()){
                	Interface.setTextArea3("INSTRUCCION A EJECUTAR : ");
                	Interface.setTextArea3(instruccion);
                    this.imprimePila();
                    Interface.setTextArea3("-----------------------");
                    JOptionPane.showMessageDialog(null, "Pulse enter para continuar con el siguiente paso.");
                }
            }
        } catch (FileNotFoundException ex) {
            
        } catch (IOException ex) {

        }
    }
    
}


